# -*- coding: utf-8 -*-
# D7Cl0ud360
# 邮箱: 18656042877@163.com
# 作者：sugar
# 公司网址： http://www.dtcloud360.com/
# Copyright 中亿丰数字科技集团有限公司
# 日期：2023-05-04 10:36:01.737010
# &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
import logging
from copy import deepcopy
from collections import defaultdict
from dtcloud import models, fields, api

STATUS = [
    ('激活', '激活'),
    ('禁用', '禁用')
]

TARGET = [
    ('full', '全屏模式'),
    ('current', '当前视图上打开(有导航)'),
    ('main', '当前视图上打开(无导航)'),
    ('new', '弹出框')
]


_logger = logging.getLogger(__name__)


class User(models.Model):
    """
    用户表,继承自res.users,添加了一些字段，以login唯一性约束
    """
    _inherit = "res.users"

    real_name = fields.Char(string='用户姓名')
    integral = fields.Integer(string='积分', default=0)
    introduction = fields.Text(string='个人介绍', default="")
    sex = fields.Selection([
        ('1', '1'),
        ('0', '0')
    ], string='性别')
    mobile = fields.Char(related='partner_id.mobile', inherited=True, readonly=False)
    avatar = fields.Char(string='头像')

    superuser = fields.Boolean(string='是否是超级管理员', default=False)
    role_ids = fields.Many2many('dt.role', 'dt_user_role', string='关联角色', help="关联角色")
    dep_id = fields.Many2one('dt.organization', string='所属部门', ondelete='restrict')  # 限制删除
    status = fields.Boolean(string='状态', default=True)

    def has_perm(self, need_perm_code, method):
        """
        判断是否有对应的权限

        :param need_perm_code: 接口api
        :param method: 权限接口请求方式
        :return: True or False
        """
        if self.superuser:
            return True
        role_ids = self.role_ids.filtered(lambda x: x.status is True)
        if not role_ids:
            _logger.info("对应角色缺失或禁用")
            return False

        button_list = role_ids.menu_ids.filtered(
            lambda x: x.mtype == 'button' and x.route == need_perm_code and x.method == method and x.status is True
        )
        if button_list:
            return True

        return False

    def menu_list(self, mid):
        """获取用户对应角色的权限"""
        menu_list_fields = ('id', "name", "seq_no", "code", "mtype",
                            "parent_id", 'route', "icon", "path", "hidden",
                            "keep_alive", "status", "target")
        button_list_fields = ('id', 'name', "parent_id", "code", "route", "method", "status", "mtype")

        if self.superuser:
            # 超级管理员，返回所有菜单
            menu_list = self.env['dt.menu'].sudo().search_read(
                [('status', '=', True), ('mtype', '=', 'menu')], fields=menu_list_fields, order="seq_no asc")
            button_list = self.env['dt.menu'].sudo().search_read(
                [('status', '=', True), ('mtype', '=', 'button')], fields=button_list_fields, order="seq_no asc"
            )
        else:
            role_ids = self.role_ids.filtered(lambda x: x.status is True)
            if not role_ids:
                return {
                    "menu_list": [],
                    "button_list": []
                }

            menu_ids = role_ids.menu_ids.filtered(
                lambda x: x.mtype == 'menu' and x.status is True
            )
            menu_list = menu_ids.read(fields=menu_list_fields)
            menu_list.sort(key=lambda ele: ele['seq_no'])

            button_list = role_ids.menu_ids.filtered(
                lambda x: x.mtype == 'button' and x.status is True
            ).read(fields=button_list_fields)

        _logger.info(f"menu_list={menu_list}")
        # 构建排序
        menu_list.sort(
            key=lambda ele: int(ele['parent_id']) if ele['parent_id'] is False else ele['parent_id'][0], reverse=True)

        # 处理父子关系
        menu_map = {menu['id']: menu for menu in menu_list if menu['parent_id']}
        root_menu_map = {menu['id']: menu for menu in menu_list if not menu['parent_id']}
        break_map = []
        # 构建普通菜单之间的关系
        menu_map_copy = deepcopy(menu_map)
        for name, menu in menu_map_copy.items():
            if menu['parent_id'][0] in menu_map:
                menu_map[menu['parent_id'][0]].setdefault('children', []).append(menu_map[name])
                del menu_map[name]
            else:
                if menu['parent_id'][0] not in root_menu_map:
                    _logger.info(f"菜单层级断裂, menu={menu}")
                    break_map.append(menu)

        _logger.info(f"menu_map=={menu_map}")
        # 构建子菜单、根菜单关系
        for menu_id, menu in menu_map.items():
            if menu['parent_id'][0] in root_menu_map:
                root_menu_map[menu['parent_id'][0]].setdefault("children", []).append(menu)
            else:
                root_menu_map[menu_id] = menu

        _logger.info(f"root_menu_map=={root_menu_map}")
        menu_list = root_menu_map.get(mid, {}).get('children', [])
        if break_map:
            menu_list.extend(break_map)
        return {
            "menu_list": menu_list,
            "button_list": {button['code']: button for button in button_list}
        }


class Role(models.Model):
    _name = 'dt.role'
    _description = '角色管理'

    name = fields.Char(string='角色名称')
    code = fields.Char(string='角色编码')
    seq_no = fields.Integer(string='排序', default=10)
    status = fields.Boolean(string='状态', default=True)
    users = fields.Many2many('res.users', 'dt_user_role', string='角色用户白名单')
    users_count = fields.Integer(string='白名单', compute='_compute_users_count', store=True)
    content = fields.Text(string='备注')

    menu_ids = fields.Many2many("dt.menu", string='关联菜单(按钮)', help="关联菜单", relation="dt_role_menu")

    _sql_constraints = [
        ('name_uniq', 'unique(name)', '角色名必须唯一!')
    ]

    @api.depends('users')
    def _compute_users_count(self):
        for role in self:
            role.users_count = len(role.users)


class Organization(models.Model):
    _name = 'dt.organization'
    _description = '组织管理'

    name = fields.Char(string='组织名称', required=True)
    parentId = fields.Many2one("dt.organization", string='上级部门', default=False, ondelete='cascade')
    child_ids = fields.One2many('dt.organization', 'parentId', string='下级部门')
    code = fields.Char(string='组织标识', index=True)
    status = fields.Boolean(string='状态', default=True)
    seq_no = fields.Integer(string='排序', default=1)
    leader = fields.Many2one('res.users', string='负责人')
    mobile = fields.Char(related='leader.mobile', inherited=True, readonly=True)
    email = fields.Char(related='leader.email', inherited=True, readonly=True)
    users = fields.One2many('res.users', 'dep_id', string='部门人员')
    user_count = fields.Integer(string='部门人数', default=0, compute='_compute_user_count', store=True)

    _sql_constraints = [
        ('name_uniq', 'unique(parentId,name)', u'同层级下该部门名称已存在!'),
        ('code_uniq', 'unique(code)', u'该编码已存在!'),
    ]

    @api.depends('users')
    def _compute_user_count(self):
        for org in self:
            org.user_count = len(org.users)


class Menu(models.Model):
    _name = 'dt.menu'
    _description = '菜单管理'

    mtype = fields.Selection([
        ('menu', '菜单'),
        ('button', '按钮'),
    ], default="menu")
    parent_id = fields.Many2one('dt.menu', string='上级菜单id', ondelete='cascade')
    code = fields.Char(string='唯一标识', required=True, index=True)
    name = fields.Char(string='菜单(按钮)名称', required=True)
    icon = fields.Char(string="菜单图标")
    method = fields.Selection([('GET', 'GET'), ('POST', 'POST'), ('PUT', 'PUT'), ('DELETE', 'DELETE')
                               ], string="请求方式", help="请求方式", store=True)
    route = fields.Char(string='菜单(按钮)路由')
    path = fields.Char(string='地址')
    seq_no = fields.Integer(string='排序', default=10)
    status = fields.Boolean(string='菜单(按钮)状态', default=True)

    child_ids = fields.One2many('dt.menu', "parent_id", auto_join=True, string='子菜单(按钮)')
    hidden = fields.Boolean(default=False, string="是否隐藏")  # 前端让加的字段
    keep_alive = fields.Boolean(default=False, string=" 保持活动")  # 前端让加的字段
    target = fields.Selection(TARGET, string="跳转方式", default='main', help="链接打开方式")

    _sql_constraints = [
        ('name_code_uniq', 'unique(name,code)', '名称、唯一标识必须唯一!'),
        ('code_uniq', 'unique(code)', '该`唯一标识`在系统中已存在，请更换!')
    ]

    @api.model
    def create(self, vals):
        if not vals.get('code'):
            vals['code'] = self.env['ir.sequence'].next_by_code('dtb.menu.key') or '/'
        return super().create(vals)
